#include <windows.h>
#include <lglcd.h>
#include <ctime>
#include "charset.h"
#include "background.h"

#define PX(x,y) ((y)*LGLCD_BMP_WIDTH+(x))
#define CH(x,y) ((y)*CHAR_W+(x))

#define OFFSET 1

#define MAXIMUM_TIME 10*60
#define TWICE_TOLERANCE 2
#define BARON_BLINK_TIME 60
#define DRAGON_BLINK_TIME 60
#define BLUE_RED_BLINK_TIME 20
#define BARON_TIME 7*60
#define DRAGON_TIME 6*60
#define BLUE_RED_TIME 5*60

class Timer {
public:
	Timer(int bl_time) : t(0), rem(0), blink(false), blink_time(bl_time) {}
	time_t t, rem;
	bool blink;
	int blink_time;
};

Timer baron(BARON_BLINK_TIME), dragon(DRAGON_BLINK_TIME), blue(BLUE_RED_BLINK_TIME), red(BLUE_RED_BLINK_TIME);

void printChar(BYTE *pixels, BYTE ch, BYTE x0, BYTE y0) {
	if (ch < '0' && ch > ':') return;
	ch = (ch - '0')*CHAR_W*CHAR_H;
	for (BYTE y = y0; y < y0 + CHAR_H && y < LGLCD_BMP_HEIGHT; ++y) {
		for (BYTE x = x0; x < x0 + CHAR_W && x < LGLCD_BMP_WIDTH; ++x) {
			pixels[PX(x,y)] = charset[ch + CH(x-x0,y-y0)];
		}
	}
}

void printTime(BYTE *pixels, int t, BYTE xc, BYTE yc) {
	BYTE xtl = xc - (CHAR_W+OFFSET)*4/2;
	BYTE ytl = yc - CHAR_H/2;
	
	BYTE minutes, seconds10, seconds1;
	if (t > 0 && t < MAXIMUM_TIME) {
		minutes = t/60.0;
		seconds10 = (t - minutes*60)/10;
		seconds1 = t - minutes*60 - seconds10*10;
	} else {
		minutes = 0;
		seconds10 = 0;
		seconds1 = 0;
	}

	printChar(pixels, minutes + '0', xtl, ytl);
	xtl += CHAR_W + OFFSET;
	printChar(pixels, ':', xtl, ytl);
	xtl += CHAR_W + OFFSET;
	printChar(pixels, seconds10 + '0', xtl, ytl);
	xtl += CHAR_W + OFFSET;
	printChar(pixels, seconds1 + '0', xtl, ytl);
}

void invert(BYTE *pixels, Timer &timer, BYTE from, BYTE to) {
	if (timer.rem >= 0 && timer.rem <= timer.blink_time) {
		timer.blink = !timer.blink;
	} else {
		timer.blink = false;
	}
	
	if (timer.blink) {
		for (BYTE y = 0; y < LGLCD_BMP_HEIGHT; ++y) {
			for (BYTE x = from; x < to; ++x) {
				int xy = PX(x,y);
				pixels[xy] = 0xFF - pixels[xy];
			}
		}
	}
}

void updateDisplay(int device, lgLcdBitmap160x43x1 &bm) {
	memcpy(bm.pixels, background, 160*43);
	
	time_t t = time(NULL);
		
	baron.rem = baron.t - t;
	dragon.rem = dragon.t - t;
	blue.rem = blue.t - t;
	red.rem = red.t - t;
	
	printTime(bm.pixels, (int) (baron.rem), 20, 35);
	printTime(bm.pixels, (int) (dragon.rem), 60, 35);		
	printTime(bm.pixels, (int) (blue.rem), 100, 35);
	printTime(bm.pixels, (int) (red.rem), 140, 35);
	
	invert(bm.pixels, baron, 0, 40);
	invert(bm.pixels, dragon, 40, 80);
	invert(bm.pixels, blue, 80, 120);
	invert(bm.pixels, red, 120, 160);
		
	lgLcdUpdateBitmap(device, &bm.hdr, LGLCD_PRIORITY_BACKGROUND);
}

DWORD WINAPI softbuttonCB(int device, DWORD buttons, const PVOID pContext) {
	time_t t = time(NULL);
	if (buttons & LGLCDBUTTON_BUTTON0) {
		baron.t = t + BARON_TIME;
	}
	if (buttons & LGLCDBUTTON_BUTTON1) {
		dragon.t = t + DRAGON_TIME;
	}
	if (buttons & LGLCDBUTTON_BUTTON2) {
		blue.t = t + BLUE_RED_TIME;
	}
	if (buttons & LGLCDBUTTON_BUTTON3) {
		red.t = t + BLUE_RED_TIME;
	}
	return ERROR_SUCCESS;
}

int main() {
	lgLcdInit();
	
	lgLcdConnectContext conCtx = {0}; 
	conCtx.appFriendlyName = "G15 Jungle Timer";
	conCtx.isAutostartable = TRUE; 
	conCtx.onConfigure.configCallback = NULL; 
	conCtx.onConfigure.configContext = NULL;
	conCtx.connection = LGLCD_INVALID_CONNECTION; 
	
	DWORD con = lgLcdConnect(&conCtx);
	
	if (con != ERROR_SUCCESS) {
		return -1;
	}
	
	lgLcdOpenByTypeContext openCtx = {0};
	openCtx.connection = conCtx.connection;
	openCtx.deviceType = LGLCD_DEVICE_BW;	
	openCtx.onSoftbuttonsChanged.softbuttonsChangedCallback = softbuttonCB;
	openCtx.onSoftbuttonsChanged.softbuttonsChangedContext = NULL;
	openCtx.device = LGLCD_INVALID_DEVICE;
	
	DWORD dev = lgLcdOpenByType(&openCtx);
	
	if (dev != ERROR_SUCCESS) {
		return -1;
	}
	
	lgLcdBitmap160x43x1 bm;
	bm.hdr.Format = LGLCD_BMP_FORMAT_160x43x1;
    
    while (true)
    {
		updateDisplay(openCtx.device, bm);
		Sleep(1000);
    }
	
	lgLcdClose(dev);
	lgLcdDisconnect(con);
	lgLcdDeInit();
	return 0;
}
